package gc;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Description 卡表
 * @Classname Card
 * @Date 2023/5/16
 * @Author sh
 **/
public class Card {

    private static final ReadWriteLock rwl = new ReentrantReadWriteLock();

    private static final Map<String, Map<String, List<String>>> cardMap = new HashMap<>();
    private static final String ZERO = "0";// 不存在跨代引用
    private static final String ONE = "1";// 存在跨代引用

    static {
        cardMap.put(ZERO, new HashMap<>());
        cardMap.put(ONE, new HashMap<>());
    }

    /**
     * 初始化卡表
     *
     * @param oldMemoryBlockStartAddressList 老年代内存空间中 每一个内存块的 起始地址 集合
     */
    public static void init(List<String> oldMemoryBlockStartAddressList) {
        if (oldMemoryBlockStartAddressList.isEmpty()) {
            return;
        }

        Map<String, List<String>> absentCrossMemoryBlockMap = cardMap.get(ZERO);
        // 模拟双重检查。这里是第一次检查
        if (!absentCrossMemoryBlockMap.isEmpty()) {
            return;
        }
        rwl.writeLock().lock();
        try {
            // 这里是第二次检查
            if (!absentCrossMemoryBlockMap.isEmpty()) {
                return;
            }
            oldMemoryBlockStartAddressList.forEach(oldMemoryBlockStartAddress -> {
                absentCrossMemoryBlockMap.put(oldMemoryBlockStartAddress, new ArrayList<>());
            });
        } finally {
            rwl.writeLock().unlock();
        }
    }

    /**
     * 跨代引用
     *
     * @param memoryBlockStartAddress 老年代 中 某一个内存块的起始地址
     * @param crossMemoryAddress      存在跨代引用的地址
     */
    public static void crossGenerationReference(String memoryBlockStartAddress, String crossMemoryAddress) {
        rwl.writeLock().lock();
        try {
            Map<String, List<String>> absentCrossMemoryBlockMap = cardMap.get(ZERO);
            Map<String, List<String>> existCrossMemoryBlockMap = cardMap.get(ONE);

            if (absentCrossMemoryBlockMap.containsKey(memoryBlockStartAddress)) {
                absentCrossMemoryBlockMap.remove(memoryBlockStartAddress);
                existCrossMemoryBlockMap.getOrDefault(memoryBlockStartAddress, new ArrayList<>())
                        .add(crossMemoryAddress);
                return;
            }

            if (existCrossMemoryBlockMap.containsKey(memoryBlockStartAddress)) {
                existCrossMemoryBlockMap.get(memoryBlockStartAddress)
                        .add(crossMemoryAddress);
            }
        } finally {
            rwl.writeLock().unlock();
        }
    }

    /**
     * 获取卡表中存在跨代引用的老年代的地址
     */
    public static Map<String, List<String>> getGcRootsOfCard() {
        rwl.readLock().lock();
        try {
            return cardMap.get(ONE);
        } finally {
            rwl.readLock().unlock();
        }
    }

}
